#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <cstdlib>
#include <new>
#include <typeinfo>
#include <list>
#include <thread> // std::thread
#include <mutex>  // std::mutex

using namespace std;

// 参考: https://blog.csdn.net/misayaaaaa/article/details/53786215
// 参考: https://github.com/applenob/Cpp_Primer_Practice/blob/master/excersize/ch04.md

// chapter 4 表达式

// 1. 表达式5 + 10 * 20 / 2的求值结果是多少？
// 运算符优先级的问题
// 主要记住小括号的利用、算术>关系>逻辑

// 表达式5 + 10 * 20 / 2的求值结果是多少？
// 等价于5 + ((10 * 20) / 2) = 105




// 2. 根据4.12节中的表，在下述表达式的合理位置添加括号，使得添加括号后运算对象的组合顺序与添加括号前一致。 (a) *vec.begin() (b) *vec.begin() + 1

解：

*(vec.begin())
(*(vec.begin())) + 1
// 括号是无视优先级和结合律的，加上括号意味着很大的改变

// 3.
// C++的设计思想是尽可能地“相信”程序员，将效率最大化。然而这种思想却有着潜在的危害，就是无法控制程序员自身引发的错误。因此 Java 的诞生也是必然，Java的思想就是尽可能地“不相信”程序员





// 4. 在下面的表达式中添加括号，说明其求值过程及最终结果。编写程序编译该（不加括号的）表达式并输出结果验证之前的推断。

12 / 3 * 4 + 5 * 15 + 24 % 4 / 2

解：

((12 / 3) * 4) + (5 * 15) + ((24 % 4) / 2) = 16 + 75 + 0 = 91


// 5. 写出下列表达式的求值结果。

-30 * 3 + 21 / 5  // -90+4 = -86
-30 + 3 * 21 / 5  // -30+63/5 = -30+12 = -18
30 / 3 * 21 % 5   // 10*21%5 = 210%5 = 0
-30 / 3 * 21 % 4  // -10*21%4 = -210%4 = -2


// 6.
// 写出一条表达式用于确定一个整数是奇数还是偶数。
// if (i % 2 == 0) /* ... */
// if (i & 0x1) /* ... */



// 7. 溢出是何含义？写出三条将导致溢出的表达式。

解：

当计算的结果超出该类型所能表示的范围时就会产生溢出。

short svalue = 32767; ++svalue; // -32768
unsigned uivalue = 0; --uivalue;  // 4294967295
unsigned short usvalue = 65535; ++usvalue;  // 0


当计算的结果超出了该类型所能表示的最大范围时就会产生溢出。


// 8. 说明在逻辑与、逻辑或及相等性运算符中运算对象的求值顺序。

解：

逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值，当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。这种策略称为 短路求值。
相等性运算符未定义求值顺序。
// 逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值，当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。这种策略称为 短路求值。
// 相等性运算符未定义求值顺序




// 9.
// 解释在下面的if语句中条件部分的判断过程。

// const char *cp = "Hello World";
// if (cp && *cp)

// 首先判断cp，cp 不是一个空指针，因此cp为真。然后判断*cp，*cp 的值是字符'H'，非0。因此最后的结果为真
// cp是一个指针，指向一个字符串，*cp是一个字符串,二者皆不为空，所以结果为真




// 10.


// 11.


// 12. 假设i、j和k是三个整数，说明表达式i != j < k的含义。

解：

这个表达式等于i != (j < k)。首先得到j < k的结果为true或false，转换为整数值是1或0，然后判断i不等于1或0 ，最终的结果为bool值
// 记住：算数>关系>逻辑
// 假设i、j和k是三个整数，说明表达式i != j < k的含义。
// 这个表达式等于i != (j < k)。首先得到j < k的结果为true或false，转换为整数值是1或0，然后判断i不等于1或0 ，最终的结果为bool值



// 13.
// 赋值运算符满足右结合律
// int i;   double d;
// d = i = 3.5; // i = 3, d = 3.0
// i = d = 3.5; // d = 3.5, i = 3





// 14. 





// 15.下面的赋值是非法的，为什么？应该如何修改？

double dval; int ival; int *pi;
dval = ival = pi = 0;
解： p是指针，不能赋值给int，应该改为：

dval = ival = 0;
pi = 0;



// 16. 尽管下面的语句合法，但它们实际执行的行为可能和预期并不一样，为什么？应该如何修改？
// 赋值语句在这里被当作条件
if (p = getPtr() != 0)
if (i = 1024)
解：

if ((p=getPtr()) != 0)
if (i == 1024)



// 17. 说明前置递增运算符和后置递增运算符的区别
// 前置的递增运算符：先算后用，后置的递增运算符：先用后算。递减一样



// 18.



// 19. 假设ptr的类型是指向int的指针、vec的类型是vector、ival的类型是int，说明下面的表达式是何含义？如果有表达式不正确，为什么？应该如何修改？

(a) ptr != 0 && *ptr++  
(b) ival++ && ival
(c) vec[ival++] <= vec[ival] 
解：

(a) 判断ptr不是一个空指针，并且ptr当前指向的元素的值也为真，然后将ptr指向下一个元素
(b) 判断ival的值为真，并且(ival + 1)的值也为真
(c) 表达式有误。C++并没有规定<=运算符两边的求值顺序，应该改为vec[ival] <= vec[ival+1]
a)：(*ptr != 0) && (*ptr++)  判断ptr指针指向的int值是否为0

(b)：判断ival和ival+1两个值是否都非0


// 20.
假设iter的类型是vector::iterator, 说明下面的表达式是否合法。如果合法，表达式的含义是什么？如果不合法，错在何处？

(a) *iter++;
(b) (*iter)++;
(c) *iter.empty();
(d) iter->empty();
(e) ++*iter;
(f) iter++->empty();
解：

(a)合法。返回迭代器所指向的元素，然后迭代器递增。
(b)不合法。因为vector元素类型是string，没有++操作。
(c)不合法。这里应该加括号。
(d)合法。判断迭代器当前的元素是否为空。
(e)不合法。string类型没有++操作。
(f)合法。判断迭代器当前元素是否为空，然后迭代器递增。


箭头运算符也是非常的重要啊！

       首先介绍下点运算符，用于获取类对象的一个成员。点运算符与箭头运算符之间的关系：

ptr—>mem   与   (*ptr).mem 等价。



(a)：合法：先对iter加1，再返回iter指向的值

(b)：不合法：返回iter指向的值为string ++操作无意义

(c)：不合法：iter是一个指针，没有empty()的成员

(d)：合法：判断iter所指向的值是否为空

(e)：不合法：*iter可以得到iter所指的字符串，但是字符串并没有++操作。

(f)：合法：首先判断iter所指向的值是否为空，再对iter加1

// 21.




// 22.




// 23.因为运算符的优先级问题，下面这条表达式无法通过编译。根据4.12节中的表指出它的问题在哪里？应该如何修改？

string s = "word";
string pl = s + s[s.size() - 1] == 's' ? "" : "s" ;
解：

加法运算符的优先级高于条件运算符。因此要改为：

string pl = s + (s[s.size() - 1] == 's' ? "" : "s") ;



// 24.




// 25.

如果一台机器上int占32位、char占8位，用的是Latin-1字符集，其中字符'q' 的二进制形式是01110001，那么表达式~'q' << 6的值是什么？

解：

首先将char类型提升为int类型，即00000000 00000000 00000000 01110001，然后取反，再左移6位，结果是-7296。




// 26.



// 27.

下列表达式的结果是什么？

unsigned long ul1 = 3, ul2 = 7;
(a) ul1 & ul2 
(b) ul1 | ul2 
(c) ul1 && ul2
(d) ul1 || ul2 
解：

(a) 3
(b) 7
(c) true
(d) ture




// 28.


// 30.
根据4.12节中的表，在下述表达式的适当位置加上括号，使得加上括号之后的表达式的含义与原来的含义相同。

(a) sizeof x + y      
(b) sizeof p->mem[i]  
(c) sizeof a < b     
(d) sizeof f() 
解：

(a) (sizeof x) + y
(b) sizeof(p->mem[i])
(c) sizeof(a) < b
(d) sizeof(f())



// 32.
解释下面这个循环的含义。

constexpr int size = 5;
int ia[size] = { 1, 2, 3, 4, 5 };
for (int *ptr = ia, ix = 0;
    ix != size && ptr != ia+size;
    ++ix, ++ptr) { /* ... */ }
解：

这个循环在遍历数组ia，指针ptr和整型ix都是起到一个循环计数的功能。


// 33.
根据4.12节中的表说明下面这条表达式的含义。

someValue ? ++x, ++y : --x, --y
解：

逗号表达式的优先级是最低的。因此这条表达式也等于：

(someValue ? ++x, ++y : --x), --y
如果someValue的值为真，x 和 y 的值都自增并返回 y 值，然后丢弃y值，y递减并返回y值。如果someValue的值为假，x 递减并返回x 值，然后丢弃x值，y递减并返回y值。



// 34.
根据本节给出的变量定义，说明在下面的表达式中将发生什么样的类型转换：

(a) if (fval)
(b) dval = fval + ival;
(c) dval + ival * cval;
需要注意每种运算符遵循的是左结合律还是右结合律。

解：

(a) fval 转换为 bool 类型
(b) ival 转换为 float ，相加的结果转换为 double
(c) cval 转换为 int，然后相乘的结果转换为 double



// 35.
假设有如下的定义：

char cval;
int ival;
unsigned int ui;
float fval;
double dval;
请回答在下面的表达式中发生了隐式类型转换吗？如果有，指出来。

(a) cval = 'a' + 3;
(b) fval = ui - ival * 1.0;
(c) dval = ui * fval;
(d) cval = ival + fval + dval;
解：

(a) 'a' 转换为 int ，然后与 3 相加的结果转换为 char
(b) ival 转换为 double，ui 转换为 double，结果转换为 float
(c) ui 转换为 float，结果转换为 double
(d) ival 转换为 float，与fval相加后的结果转换为 double，最后的结果转换为char




// 36.
假设 i 是int类型，d 是double类型，书写表达式 i*=d 使其执行整数类型的乘法而非浮点类型的乘法。

解：

i *= static_cast<int>(d);




// 37.
练习4.37 用命名的强制类型转换改写下列旧式的转换语句。

int i; double d; const string *ps; char *pc; void *pv;
(a) pv = (void*)ps;
(b) i = int(*pc);
(c) pv = &d;
(d) pc = (char*)pv;
解：

(a) pv = static_cast<void*>(const_cast<string*>(ps));
(b) i = static_cast<int>(*pc);
(c) pv = static_cast<void*>(&d);
(d) pc = static_cast<char*>(pv);



// 38.
说明下面这条表达式的含义。

double slope = static_cast<double>(j/i);
解：

将j/i的结果值转换为double，然后赋值给slope。
















int main()
{
   cout << "bool:\t\t" << sizeof(bool) << " bytes" << endl << endl;

	cout << "char:\t\t" << sizeof(char) << " bytes" << endl;
	cout << "wchar_t:\t" << sizeof(wchar_t) << " bytes" << endl;
	cout << "char16_t:\t" << sizeof(char16_t) << " bytes" << endl;
	cout << "char32_t:\t" << sizeof(char32_t) << " bytes" << endl << endl;

	cout << "short:\t\t" << sizeof(short) << " bytes" << endl;
	cout << "int:\t\t" << sizeof(int) << " bytes" << endl;
	cout << "long:\t\t" << sizeof(long) << " bytes" << endl;
	cout << "long long:\t" << sizeof(long long) << " bytes" << endl << endl;

	cout << "float:\t\t" << sizeof(float) << " bytes" << endl;
	cout << "double:\t\t" << sizeof(double) << " bytes" << endl;
	cout << "long double:\t" << sizeof(long double) << " bytes" << endl << endl;
    printf("hello c++ \n");
}